# -*- coding:UTF-8 -*-
import aiohttp
import asyncio
import os
import re
import time
import subprocess
import pymysql
import pypinyin
import tqdm

FLAGS = {}
# 保存目录
DEST_DIR = 'downloads/'
headers = {
    "User-Agent": 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.13 Safari/537.36',
    "Referer": "http://www.v2ex.com/signin"
}


# 获取链接,下载文件
async def fetch(session: aiohttp.ClientSession, url: str, path: str, flag: str):
    async with session.get(url, headers=headers, timeout=5000) as resp:
        try:
            with open(path, 'wb') as fd:
                while 1:
                    chunk = await resp.content.read(1024)  # 每次获取1024字节
                    if not chunk:
                        break
                    fd.write(chunk)
        except Exception as e:
            return flag
    return flag


async def begin_download(sem, session: aiohttp.ClientSession, url: str, path: str, flag: str):
    # 控制协程并发数量
    with (await sem):
        return await fetch(session, url, path, flag)


async def download(sem: asyncio.Semaphore):
    tasks = []
    async with aiohttp.ClientSession() as session:
        for flag in FLAGS.items():
            # 创建路径以及url
            # 'downloads/血之荣耀.apk'
            path = os.path.join(DEST_DIR, '%s.apk' % hp(flag[1]))
            # 构造一个协程列表
            tasks.append(asyncio.ensure_future(
                begin_download(sem, session, "http://pc6.com/down.asp?id=%s" % flag[0], path,
                               "%s|%s|%s" % (flag[0], flag[1], path))))
        # 等待返回结果
        tasks_iter = asyncio.as_completed(tasks)
        # 创建一个进度条
        fk_task_iter = tqdm.tqdm(tasks_iter, total=len(FLAGS))
        for coroutine in fk_task_iter:
            res = await coroutine
            content = str(res).split("|")
            print(content[0:2], '下载完成')
            getApkMsg(content[2], content[1])


def hp(word):
    s = ''
    for i in pypinyin.pinyin(word, style=pypinyin.NORMAL):
        s += ''.join(i)
    return s


# 获取apk信息
def getApkMsg(path, apkName):
    p = subprocess.Popen("aapt dump badging %s" % path, stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         stdin=subprocess.PIPE, shell=True)
    (output, err) = p.communicate()
    msg = re.findall('package: name=(.*?) versionCode[.*\S*\s]*launchable-activity: name=(.*?)  label', output.decode())
    if msg.__len__() >= 1:
        saveAPKpackageLauncher(msg[0][0], msg[0][1], apkName, path)
    else:
        saveAPKpackageLauncher("", "", apkName, path)


# 保存apk包名启动类
def saveAPKpackageLauncher(package, launcher, apkName, FilePath):
    if package.__eq__(""):
        sql = f"update pc6 set FilePath='%s' , isDown=1 where appName='%s'" % (FilePath, apkName)
    else:
        sql = f"update pc6 set packageName=%s , launcher=%s , FilePath='%s' , isDown=1 where appName='%s'" % (package, launcher, FilePath, apkName)
    try:
        cursor.execute(sql)
        db.commit()
    except:
        # 如果发生错误则回滚
        db.rollback()


# 查询下载地址
def selectDownAddress(start_ID, end_ID):
    cursor.execute("select *  from pc6  where _id>=%s and _id<%s and isDown=0" % (start_ID, end_ID))
    allNo = cursor.fetchall()
    if allNo.__len__() > 0:
        for i in allNo:
            FLAGS[i[1]] = i[2]
    else:
        print("未查询到数据")


# 插入序号
def installNO(cursor, db, NO, appName="", downAddress=""):
    # 'insert into apk3(NO,appName,downAddress) values (277982,星王高爆版下载 5.0,https://dlres.63yx.com/h5zy/10111-721343/xwgbb.apk)'
    sql = "insert into apk3(No,appName,downAddress) values (%d,'%s','%s')" % (NO, appName, downAddress)
    cursor.execute(sql)
    db.commit()
    db.rollback()


if __name__ == '__main__':
    db = pymysql.connect("localhost", "root", "164531", "appmsg")
    cursor = db.cursor()
    selectDownAddress(1, 10)
    # 创建目录
    os.makedirs(DEST_DIR, exist_ok=True)
    # 获取事件循环
    lp = asyncio.get_event_loop()
    start = time.time()
    # 创建一个信号量以防止DDos
    sem = asyncio.Semaphore(1)
    lp.run_until_complete(download(sem))
    end = time.time()
    lp.close()
    print('共耗时:', end - start)
